package com.lzx.hbh_system.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.lzx.hbh_system.util.responseEntity.RespOutMsgHeader;
import com.lzx.hbh_system.util.responseEntity.ResponseView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 用于用户上传图片到Gtiee仓库的工具配置类
 */
@Component
public class GitHubBucketUtil {
    /**
     * 码云分配的私人令牌
     */
    @Value("${github.bucket.access-token}")
    private String ACCESS_TOKEN;

    /**
     * 所属地址 - 指码云仓库 个人用户名
     */
    @Value("${github.bucket.owner}")
    private String OWNER;

    /**
     * 仓库名称 - 指码云仓库 仓库名称
     */
    @Value("${github.bucket.repo-name}")
    private String REPO_NAME;

    /**
     * 上传文件的 - 文件信息
     */
    @Value("${github.bucket.create-repos-message}")
    private String CREATE_REPOS_MESSAGE;

    /**
     * 更新文件的 - 文件信息
     */
    @Value("${github.bucket.update-repos-message}")
    private String UPDATE_REPOS_MESSAGE;

    /**
     * 文件前缀 - 指上传的图片的路径，在img路径下，以每天的日期为子文件夹进行存储，上传地址可以自定义
     */
    private static final String IMG_FILE_DEST_PATH = "img/%s/";
    /**
     *   X jsdelivr Github外链加速地址 { owner } / { repos } - 2022-5-18 CDN加速暂时被BAN
     *   X 使用 raw.fastgit.org 加速Github 2022-5-18 不能访问 403
     * 使用 github自己的 raw.githubusercontent.com 可以访问，可能需要访问速度快的IP并配置访问电脑host文件， 以及刷新DNS缓存才能正常访问
     */
//    private static final String JSDELIVR_URL = "https://cdn.jsdelivr.net/gh/%s/%s/";
    private static final String JSDELIVR_URL = "https://raw.githubusercontent.com/%s/%s/main/";
    /**
     * 新建文件
     * <p>
     * owner*   仓库所属空间地址(企业、组织或个人的地址path)-用户名
     * repo*    仓库路径
     * path*    文件的路径
     * content* 文件内容, 要用 base64 编码
     * message* 提交信息
     * <p>
     * %s =>仓库所属空间地址(企业、组织或个人的地址path)  (owner)
     * %s => 仓库路径(repo)
     * %s => 文件的路径(path)
     */
    // 由于gitee的防盗机制，第三方编辑器访问gitee地址时会重定向到gitee、LOGO导致无法访问已经上传的地址
    // 转而使用github
//    private static final String CREATE_REPOS_URL = "https://gitee.com/api/v5/repos/%s/%s/contents/%s";
//            仓库上传/更新文件API /repos/{owner}/{repo}/contents/{path}
//            如果给定body的sha字段值会自动更新当前文件
//            注意地址末尾加上分支名称 '?ref=main'
    private static final String CREATE_REPOS_URL = "https://api.github.com/repos/%s/%s/contents/%s?ref=main";

    // 提交文件
    public ResponseView uploadUImg(MultipartFile file,String userCode) throws IOException{
        // 初始化返回视图
        ResponseView responseView = new ResponseView();
        if(ObjectUtils.isEmpty(file)){
            // 返回响应消息
            responseView.setRespOutMsgHeader(RespOutMsgHeader.error(false,"文件不能为空，请选择文件上传！",500));
            return responseView;
        }

        String trueFileName = file.getOriginalFilename(); // 获取文件原始名称
        // 断言 trueFileName 不为空
        assert trueFileName != null;
        // 后缀
        String suffix = trueFileName.substring(trueFileName.lastIndexOf("."));
        // 文件名
        String fileName = DateUtil.format(new Date(),"yyyy_MM_dd") + '_' + IdUtil.randomUUID() + suffix;
        // 转Base64
        String paramImgFile = Base64.encode(file.getBytes());
        // 转存到gitee
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("content",paramImgFile); // 公共- 请求参数 2 文件Base64转码
        String format = String.format(IMG_FILE_DEST_PATH, userCode != null ? userCode : "unknownUserCode");
        // 没有携带sha值 - 新增文件
        String targetDir = format + fileName; // 上传图片路径 新文件名称
        String requestUrl = String.format(CREATE_REPOS_URL,OWNER,REPO_NAME,targetDir); // 根据常量定义的格式格式化请求URl
        paramMap.put("message",CREATE_REPOS_MESSAGE);// 新建- 请求参数 1 上传文件消息
        return updateFileHandle(requestUrl,paramMap,fileName,targetDir);
    }

    /**
     * 上传文件方法  上传新文件
     * @param paramMap
     * @param originfileName
     * @return
     */
    public ResponseView updateFileHandle(String uploadUrl,Map<String,Object> paramMap,String originfileName,String path){
        System.out.println("文件操作函数执行！");
        // 初始化返回视图
        ResponseView responseView = new ResponseView();
        if (originfileName == null) {
            responseView.setRespOutMsgHeader(RespOutMsgHeader.error(false,"文件上传失败，需要提供源文件名称！！",500));
            return responseView;
        }
        JSONObject payload = new JSONObject();
        payload.put("message",paramMap.get("message"));
        payload.put("content",paramMap.get("content"));
        // 携带Map作为body参数，发送文件上传请求 返回JSON格式的字符串
        // 解析JSON字符串
        // 请求处理参数，将请求地址、载体、请求方法传入获得JSON格式结果集
        JSONObject jsonObject = requestHandle(uploadUrl,payload,HttpMethod.PUT);
        System.out.println("文件上传函数执行！");
        System.out.println("请求地址："+uploadUrl);
        if (jsonObject.getObj("commit") != null){
            // 初始化响应集合Map
            Map<String,Object> map = new HashMap<>();
            // 获取响应JSON的content内容
            JSONObject content = jsonObject.getJSONObject("content"); // 获取当前接口的响应内容实体
            // 获取文件的访问地址
            String accessURL = String.format(JSDELIVR_URL,OWNER,REPO_NAME) + path;
            System.out.println("新头像访问地址："+accessURL);
            String sha = content.getStr("sha"); // 更新后的新文件的 Blob SHA，可通过 [获取仓库具体路径下的内容] API 获取，用于更新或者删除文件
            map.put("file_name",originfileName);
            map.put("sha",sha); // 响应新的sha值
            map.put("access_url",accessURL);
            responseView.setRespOutMsgHeader(RespOutMsgHeader.success(1,true,"文件更新成功！！"));
            responseView.setMain(map);
            return responseView;
        }else{
            responseView.setRespOutMsgHeader(RespOutMsgHeader.error(false,"文件上传失败，仓库转储错或者服务出错！！",500));
            return responseView;
        }
    }

    /**
     * 获取Gitee仓库相关文件信息 目的 获取对应的SHA值进行更新或者删除操作
     * @param format
     * @param originName
     * @return
     */
/*
    public JSONObject getFileInfo(String format,String originName){
        System.out.println(originName);
        String targetDir = format + originName; // 上传图片路径 源文件名称
        String requestUrl = String.format(CREATE_REPOS_URL,OWNER,REPO_NAME,targetDir); // 根据常量定义的格式格式化请求URl
        System.out.println("获取源文件信息：");
        System.out.println("请求地址："+requestUrl);
        // 解析JSON字符串
        JSONObject jsonObject = requestHandle(requestUrl,null,HttpMethod.GET);
        return jsonObject;
    }
*/

    /**
     * 删除文件请求函数
     * 载体需要 message 、 sha 值
     * @return
     */
/*    public JSONObject deleteFile(String requestUrl,JSONObject payload){
        System.out.println("删除函数执行！");
        System.out.println("请求地址："+requestUrl);
        // 解析JSON字符串
        JSONObject jsonObject = requestHandle(requestUrl,payload,HttpMethod.DELETE);
        return jsonObject;
    }*/

    /**
     * 向Github的API请求接口方法
     * @param requestURL 请求API地址
     * @param payload 载体body
     * @param requestMethod 请求方式
     * @return JSONObject JSON字符串 - 响应结果
     */
    public JSONObject requestHandle(String requestURL,JSONObject payload,HttpMethod requestMethod){
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        httpHeaders.set(HttpHeaders.ACCEPT,"application/vnd.github.v3+json");
        httpHeaders.set(HttpHeaders.AUTHORIZATION, "token " + ACCESS_TOKEN);
        ResponseEntity<String> responseEntity;
        if (payload == null){
            responseEntity = new RestTemplate().exchange(requestURL, requestMethod,
                    new HttpEntity<String>(null, httpHeaders), String.class);
        }else{
//            System.out.println(payload);
            responseEntity = new RestTemplate().exchange(requestURL, requestMethod,
                    new HttpEntity<String>(payload.toString(), httpHeaders), String.class);
        }
        return JSONUtil.parseObj(fomatJsonStr(Objects.requireNonNull(responseEntity.getBody())));
    }

    /**
     * 格式化JSON字符串 多余的 符号
     * @param jsonstr
     * @return
     */
    public String fomatJsonStr(String jsonstr){
        System.out.println(jsonstr);
        int i = jsonstr.indexOf("{");
        jsonstr = jsonstr.substring(i);
        int p = jsonstr.lastIndexOf("}");
        if (i==0){
            jsonstr = jsonstr.substring(i,p+1);
        }else{
            jsonstr = jsonstr.substring(i-1,p+1);
        }
        jsonstr = jsonstr.replaceAll("\\\\","");
        return jsonstr.trim();
    }
}

